import math
import cv2
import numpy as np
import pyzbar.pyzbar as pyzbar
import qrcode
from PIL import Image
import time


def welcome():
    print("请选择你要做的操作:")
    print("1.生成二维码")
    print("2.识别二维码及角度")
    choose_a = input()
    if choose_a == '1':
        print("1.将txt文件内数据生成二维码")
        print("2.自定义数据生成二维码")
        choose_b = input()
        if choose_b == '1':
            with open('resource.txt', encoding='UTF-8') as file_obj:
                text = file_obj.read()
                print(text)
            qrcodecreate(text)
        if choose_b == '2':
            # 二维码内容
            text = input("")
            qrcodecreate(text)

    if choose_a == '2':
        detect()


def qrcodecreate(text):
    # 生成二维码
    img = qrcode.make(data=text)
    # # 直接显示二维码
    # img.show()
    # 保存二维码为文件
    # img=cv2.resize(1024,1024)
    img.save("qrcode.jpg")

    # 加载背景图片
    bk_img = cv2.imread("qrcode.jpg")
    # 在图片上添加文字信息
    bk_img = cv2.resize(bk_img, (480, 480), 0, 0)

    shape_x = bk_img.shape[0]
    shape_y = bk_img.shape[1]
    texta = "Mobot    " + text
    cv2.putText(bk_img, texta, (int(shape_x / 2) - 80, 40), cv2.FONT_HERSHEY_SIMPLEX,
                0.5, (218, 123, 233), 2, cv2.LINE_AA)

    ptStart = (int(shape_x / 2), 0)
    ptEnd = (int(shape_x / 2), 20)
    point_color = (0, 0, 0)  # BGR
    thickness = 3
    lineType = 4
    cv2.line(bk_img, ptStart, ptEnd, point_color, thickness, lineType)

    ptStart = (int(shape_x / 2), int(shape_y) - 20)
    ptEnd = (int(shape_x / 2), int(shape_y))
    point_color = (0, 0, 0)  # BGR
    thickness = 3
    lineType = 4
    cv2.line(bk_img, ptStart, ptEnd, point_color, thickness, lineType)

    ptStart = (0, int(shape_y / 2))
    ptEnd = (20, int(shape_y / 2))
    point_color = (0, 0, 0)  # BGR
    thickness = 3
    lineType = 4
    cv2.line(bk_img, ptStart, ptEnd, point_color, thickness, lineType)

    ptStart = (int(shape_x) - 20, int(shape_y / 2))
    ptEnd = (int(shape_x), int(shape_y / 2))
    point_color = (0, 0, 0)  # BGR
    thickness = 3
    lineType = 4
    cv2.line(bk_img, ptStart, ptEnd, point_color, thickness, lineType)

    icon = Image.open('2.jpg')

    cv2.imwrite("x5y5.jpg", bk_img)

    cv2.waitKey(0)

    # 保存图片
    # cv2.imshow('x5y5.jpg', bk_img)
    bk_img = Image.open('x5y5.jpg')
    assert isinstance(bk_img, Image.Image)
    # 参数设置logo的大小
    factor = 6
    size_w = int(shape_x / factor)
    size_h = int(shape_y / factor)
    icon_w, icon_h = icon.size
    if icon_w > size_w:
        icon_w = size_w
    if icon_h > size_h:
        icon_h = size_h
    # 重新设置logo的尺寸
    icon = icon.resize((icon_w, icon_h), Image.ANTIALIAS)
    # 得到画图的x，y坐标，居中显示
    w = int((shape_x - icon_w) / 2)
    h = int((shape_y - icon_h) / 2)
    # 黏贴logo照
    bk_img.paste(icon, (w, h), mask=None)
    bk_img.show()
    bk_img.save('/home/wang/Desktop/qrcode_list/x5y5.jpg')


def checkRatioOfContours(index, contours, hierarchy):
    firstChildIndex = hierarchy[0][index][2]
    secondChildIndex = hierarchy[0][firstChildIndex][2]
    firstArea = cv2.contourArea(contours[index]) / (
            cv2.contourArea(contours[firstChildIndex]) + 1e-5)
    secondArea = cv2.contourArea(contours[firstChildIndex]) / (
            cv2.contourArea(contours[secondChildIndex]) + 1e-5)
    return ((firstArea / (secondArea + 1e-5)) > 1 and \
            ((firstArea / (secondArea + 1e-5)) < 10))


def isPossibleCorner(contourIndex, levelsNum, contours, hierarchy):
    # if no chirld, return -1
    chirldIdx = hierarchy[0][contourIndex][2]
    level = 0
    while chirldIdx != -1:
        level += 1
        chirldIdx = hierarchy[0][chirldIdx][2]
    if level >= levelsNum:
        return checkRatioOfContours(contourIndex, contours, hierarchy)
    return False


def getContourWithinLevel(levelsNum, contours, hierarchy):
    # find contours has 3 levels
    patterns = []
    patternsIndices = []
    for contourIndex in range(len(contours)):
        if isPossibleCorner(contourIndex, levelsNum, contours, hierarchy):
            patterns.append(contours[contourIndex])
            patternsIndices.append(contourIndex)
    return patterns, patternsIndices


def convert_img_to_binary(img):
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # adaptiveThreshold 自适应阈值 图像 处理
    binary_img = cv2.adaptiveThreshold(
        gray,
        255,  # Value to assign
        cv2.ADAPTIVE_THRESH_MEAN_C,  # Mean threshold
        cv2.THRESH_BINARY,
        11,  # Block size of small area
        2,  # Const to substract
    )
    return binary_img


def getContours(img):
    binary_img = convert_img_to_binary(img)  # do adaptiveThreshold
    thresholdImage = cv2.Canny(binary_img, 100, 200)  # Edges by canny edge detection(边缘检测算法)
    _, contours, hierarchy = cv2.findContours(thresholdImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    return thresholdImage, contours, hierarchy


def isParentInList(intrestingPatternIdList, index, hierarchy):
    parentIdx = hierarchy[0][index][3]
    while (parentIdx != -1) and (parentIdx not in intrestingPatternIdList):
        parentIdx = hierarchy[0][parentIdx][3]
    return parentIdx != -1


def getCenterOfMass(contours):
    pointList = []
    for i in range(len(contours)):
        moment = cv2.moments(contours[i])
        centreOfMassX = int(moment['m10'] / moment['m00'])
        centreOfMassY = int(moment['m01'] / moment['m00'])
        pointList.append([centreOfMassX, centreOfMassY])
    return pointList


def findmin(a, b):
    if a > b:
        return b
    else:
        return a


def findmax(a, b):
    if a > b:
        return a
    else:
        return b


def point2area(points, img, color):
    # img = cv2.imread(img)
    res = cv2.fillPoly(img, [np.array(points)], color)


def decodeDisplay(image):
    barcodes = pyzbar.decode(image)  # 通过 zbar 自带的检测 程序 decode 得到

    if barcodes != []:
        edges = cv2.Canny(image, 50, 200)
        ls = cv2.HoughLines(edges, 1, np.pi / 180, 100)
        l1 = ls[:, 0, :]
        print(l1)
        thresholdImage, contours, hierarchy = getContours(image)
        img_show = cv2.cvtColor(thresholdImage, cv2.COLOR_GRAY2BGR)
        cv2.drawContours(img_show, contours, -1, (0, 255, 0), 3)
        # cv2.imshow("Display Image", img_show)
        # cv2.waitKey(0)

        levelsNum = 3
        patterns, patternsIndices = getContourWithinLevel(levelsNum, contours, hierarchy)
        img_show = cv2.cvtColor(thresholdImage, cv2.COLOR_GRAY2BGR)
        # cv2.drawContours(img_show, patterns, -1, (0, 255, 0), 3)
        # cv2.imshow("Display Image", img_show)
        # cv2.waitKey(0)
        # print(patterns)

        while len(patterns) < 3 and levelsNum > 0:
            levelsNum -= 1
            patterns, patternsIndices = getContourWithinLevel(levelsNum, contours, hierarchy)

        interstingPatternList = []

        print(len(patterns))
        if len(patterns) == 3:
            for patternIndex in range(len(patterns)):
                x, y, w, h = cv2.boundingRect(patterns[patternIndex])
                interstingPatternList.append(patterns[patternIndex])
                cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
            return patterns

        elif len(patterns) > 3:
            # sort from small to large
            patternAreaList = np.array(
                [cv2.contourArea(pattern) for pattern in patterns])
            areaIdList = np.argsort(patternAreaList)
            # get patterns without parents
            intrestingPatternIdList = []
            for i in range(len(areaIdList) - 1, 0, -1):
                index = patternsIndices[areaIdList[i]]
                if hierarchy[0][index][3] == -1:
                    intrestingPatternIdList.append(index)
                else:
                    # We can make sure the parent must appear before chirld because we sorted the list by area
                    if not isParentInList(intrestingPatternIdList, index, hierarchy):
                        intrestingPatternIdList.append(index)
            img_show = cv2.cvtColor(thresholdImage, cv2.COLOR_GRAY2BGR)
            for intrestingPatternId in intrestingPatternIdList:
                x, y, w, h = cv2.boundingRect(contours[intrestingPatternId])

                # cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
                interstingPatternList.append(contours[intrestingPatternId])
        # cv2.imshow("Display Image", image)
        # cv2.waitKey(0)

        centerOfMassList = getCenterOfMass(interstingPatternList)

        # 显示矩形框中心点位置
        for centerOfMass in centerOfMassList:
            cv2.circle(image, tuple(centerOfMass), 3, (255, 0, 255))
        cv2.imshow("Display Image", image)
        cv2.waitKey(0)

        # 剔除不合格的中心点
        if len(centerOfMassList) == 3:

            AX = centerOfMassList[0][0]
            AY = centerOfMassList[0][1]
            BX = centerOfMassList[1][0]
            BY = centerOfMassList[1][1]
            CX = centerOfMassList[2][0]
            CY = centerOfMassList[2][1]

            AB_AC = (BX - AX) * (CX - AX) + (BY - AY) * (CY - AY)
            BA_BC = (AX - BX) * (CX - BX) + (AY - BY) * (CY - BY)
            CB_CA = (BX - CX) * (AX - CX) + (BY - CY) * (AY - CY)
            AB_dist = math.sqrt((AX - BX) * (AX - BX) + (AY - BY) * (AY - BY))
            AC_dist = math.sqrt((AX - CX) * (AX - CX) + (AY - CY) * (AY - CY))
            CB_dist = math.sqrt((BX - CX) * (BX - CX) + (BY - CY) * (BY - CY))
            success = 1
            fail = 0
            if AB_dist != 0 and AC_dist != 0 and CB_dist != 0:
                qrcode_find = success
                A_angle = math.acos(AB_AC / (AB_dist * AC_dist))
                B_angle = math.acos(BA_BC / (AB_dist * CB_dist))
                C_angle = math.acos(CB_CA / (CB_dist * AC_dist))
                # print("A_angle", A_angle)
                # print("B_angle", B_angle)
                # print("C_angle", C_angle)
            else:
                qrcode_find = fail

            # print("AB_AC",AB_AC)
            # print("BA_BC", BA_BC)
            # print("CB_CA", CB_CA)
            #
            # print("AB_dist", AB_dist)
            # print("AC_dist", AC_dist)
            # print("CB_dist", CB_dist)

            if qrcode_find == 1:
                for interstingIndex in range(len(interstingPatternList)):
                    x, y, w, h = cv2.boundingRect(interstingPatternList[interstingIndex])
                    cv2.rectangle(image, (x, y), (x + w, y + h), (255, 255, 0), 2)
                    point_value = [x, y]
                    point_text = ''
                    xx = "%.2f " % x
                    yy = "%.2f " % y
                    point_text = xx + yy
                    # point_text =xx++yy
                    cv2.putText(image, point_text, (x, y), cv2.FONT_HERSHEY_SIMPLEX,
                                .3, (0, 0, 225), 1)

                if A_angle < 1.60 and A_angle > 1.50:
                    if abs(B_angle - C_angle) < 0.1:
                        print("A is angle 90: ", AX, AY)
                        AY = -AY
                        BY = -BY
                        CY = -CY
                        angleAB = math.atan2((BY - AY), (BX - AX))
                        angleAC = math.atan2((CY - AY), (CX - AX))
                        if angleAB < 0:
                            angleAB = angleAB + 2 * math.pi
                        if angleAC < 0:
                            angleAC = angleAC + 2 * math.pi
                        theta = findmin(angleAC, angleAB)
                        # if abs(angleAC - angleAB) > math.pi:
                        #     xangle = findmin(angleAC, angleAB)
                        # else:
                        #     xangle = findmax(angleAC, angleAB)

                        # print("angleAB",angleAB)
                        # print("angleAC", angleAC)
                        print("theta", theta)
                elif B_angle < 1.6 and B_angle > 1.50:
                    if abs(A_angle - C_angle) < 0.1:
                        print("B is angle 90:", BX, BY)
                        AY = -AY
                        BY = -BY
                        CY = -CY
                        angleBA = math.atan2((AY - BY), (AX - BX))
                        angleBC = math.atan2((CY - BY), (CX - BX))
                        # print("angleBA", angleBA)
                        # print("angleBC", angleBC)
                        if angleBA < 0:
                            angleBA = angleBA + 2 * math.pi
                        if angleBC < 0:
                            angleBC = angleBC + 2 * math.pi
                        theta = findmin(angleBA, angleBC)
                        # if abs(angleBA - angleBC) > math.pi:
                        #     xangle = findmin(angleBA, angleBC)
                        # else:
                        #     xangle = findmax(angleBA, angleBC)
                        # print("angleBA",angleBA)
                        # print("angleBC", angleBC)
                        print("theta", theta)
                elif C_angle < 1.6 and C_angle > 1.50:
                    if abs(A_angle - B_angle) < 0.1:
                        AY = -AY
                        BY = -BY
                        CY = -CY
                        print("C is angle 90:", CX, CY)
                        angleCB = math.atan2((BY - CY), (BX - CX))
                        angleCA = math.atan2((AY - CY), (AX - CX))
                        # print("angleCB", angleCB)
                        # print("angleCA", angleCA)
                        if angleCB < 0:
                            angleCB = angleCB + 2 * math.pi
                        if angleCA < 0:
                            angleCA = angleCA + 2 * math.pi

                        theta = findmin(angleCB, angleCA)
                        # if abs(angleCB - angleCA) > math.pi:
                        #     xangle = findmin(angleCB, angleCA)
                        # else:
                        #     xangle = findmax(angleCB, angleCA)
                        # print("angleCB",angleCB)
                        # print("angleCA", angleCA)
                        print("theta", theta)
    for barcode in barcodes:
        (x, y, w, h) = barcode.rect
        print(barcode)
        (point0, point1, point2, point3) = barcode.polygon
        # print("point0", point0)
        # print("point1", point1)
        # print("point2", point2)
        # print("point3", point3)
        cv2.rectangle(image, (x, y), (x + w, y + h), (225, 225, 225), 10)
        # 提取二维码数据为字节对象，所以如果我们想在输出图像上
        # 画出来，就需要先将它转换成字符串
        # print(barcode.data)
        # barcodeData = barcode.data.decode("utf-8")
        # barcodeType = barcode.type
        point0_x = point0[0]
        point0_y = point0[1]
        point1_x = point1[0]
        point1_y = point1[1]
        point2_x = point2[0]
        point2_y = point2[1]
        point3_x = point3[0]
        point3_y = point3[1]

        points = [(point0_x, point0_y), (point1_x, point1_y), (point2_x, point2_y), (point3_x, point3_y)]
        print(points)
    if barcodes != []:
        point2area(points, image, [255, 255, 255])
        edges = cv2.Canny(image, 50, 200)
        ls = cv2.HoughLines(edges, 1, np.pi / 180, 100)
        print(ls)
        # 绘出图像上条形码的数据和条形码类型
        # text = "{} ({})".format(barcodeData, barcodeType)
        # cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
        #             .5, (225, 225, 225), 2)
    return image


def detect():
    # img = cv2.imread('1.jpg')
    # # cv2.imshow( "Display Image", img)
    # # cv2.waitKey(0)
    # decodeDisplay(img)
    camera = cv2.VideoCapture(0)
    while True:
        start = time.clock()
        ret, frame = camera.read()
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        im = decodeDisplay(gray)
        end = time.clock()
        print('Running time: %s Seconds' % (end - start))
        cv2.waitKey(5)
        cv2.imshow("camera", im)
        # 如果按键q则跳出本次循环
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
    camera.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    welcome()
